﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Game
{

    class Scheduler  // 預計MA 目前是GA
    {

        Player _P1, _P2;
         List<ACTION_MODE> _actionlist;
        Func<List<int>,int> _evalfun ;        
        Random _rand = new Random();
        Map _tempMap;
        Map _Now;
        UI _data;
        int _side;
	List<Solution> _sols;
	const int _population = 20;
	const int _generation = 30;
	int _mtrate;
	
	int _bestSol;	
	int _num;
	int _bestIndex;
	int _nowG;
       
    public Scheduler(UI data,int side,List<ACTION_MODE> actionList)
    {
        _side = side;
         _actionlist = actionList;
        _data = data;
        _P1 = new Player(data.GetPlayer(side));
        _P2 = new Player(data.GetPlayer(side^1));       
        _nowG = 0;
        _Now = data.Map;
        _sols = new List<Solution>();
        for (int i = 0; i < _population; i++)
        {
            Solution tempSol = new Solution(_P1.Slimes.Count);
            Eval(tempSol);
            _sols.Add(tempSol);
        }
        _bestSol = _sols[0].Fitness;
        for (int i = 0; i < _sols.Count(); i++)
        {
            if (_sols[i].Fitness< _bestSol)
            {
                _bestSol = _sols[i].Fitness;
                _bestIndex = i;
            }
        }
        BestCounter();
    }




        public void Run()
        {
            while (!Stop())
            {
                for (int i = 0; i < _population / 2; i++)
                {
                    int fa = 0;
                    int ma = 0;
                    Selection(ref fa, ref ma);
                    CrossOver(fa, ma);
                    CrossOver(ma, fa);
                }

                for (int i = 0; i < _population; i++)
                {
                    if (i == _bestIndex)
                    {
                        continue;
                    }
                    Mutation(_sols[i]);
                }


                while (_sols.Count > _population)
                {
                    int temp = _rand.Next(_sols.Count);
                    if (temp == _bestIndex)
                    {
                        continue;
                    }
                    else if (temp < _bestIndex)
                    {
                        --_bestIndex;
                    }
                    if (_sols[temp].Fitness == _bestSol)
                    {
                        if (_num == 1) { continue; }// 保留最佳解
                        else
                        {
                            --_num;
                        }
                    }
                    _sols.RemoveAt(temp);
                }                
            }


        }
        bool Stop()
        {
            _nowG++;

            if (_nowG >= _generation)
            {
                return true;
            }
            if (_num >= _population-5)
            {
                return true;
            }
            return false;
        }


        void Selection(ref int fa, ref int ma)
        {
            // n tournament
            int n = 4;
            fa = _rand.Next(_population);
            ma = _rand.Next(_population);
            int R = 1;
            if (_num >= _population / 3)
            {
                R = 0;
            }
            else if (_num == 1)
            {
                R = 90;
            }
            if (_rand.Next(100) < R)
            {
                ma = _bestIndex;
            }


            if (_sols[fa].Fitness > _sols[ma].Fitness)
            {

                int temp = ma;
                ma = fa;
                fa = temp;
            }
            for (int i = 2; i < n; i++)
            {
                int temp = _rand.Next(_population);
                if (_sols[temp].Fitness < _sols[fa].Fitness)
                {
                    ma = fa;
                    fa = temp;
                }
                else if (_sols[temp].Fitness < _sols[ma].Fitness)
                {
                    ma = temp;
                }
            }
        }
        void CrossOver(int fa, int ma)
        {
            Solution spring = new Solution((_sols[fa].CrossOver(_sols[ma])).Order);
            Eval(spring);
            /*
            if (_nowG % 10 == 0)
            {
                Learning(spring);
            }*/
            int temp = spring.Fitness;
            _sols.Add(spring);

            if (temp < _bestSol)
            {
                _bestSol = temp;
                _bestIndex = _sols.Count - 1;
                BestCounter();
            }
            else if (temp == _bestSol)
            {
                ++_num;
            }

        }
        void Mutation(Solution s) {
            int temp = _mtrate;
            if (_num >= _population / 2)
            {
                temp += 7;
            }
            else if (_num >= _population * 3 / 4)
            {
                temp *= 2;
            }

            if (_rand.Next(100) < temp)
            {
                s.Mutation();
                Eval(s);
            }
        }
        void Learning(Solution s) { 
            //還沒做
        }
        public void Update(Map newMap){
            _Now = newMap;
        }
        public int Answer()
        {
            return _bestSol;
        }
        public List<int> Order
        {
            get { return  _sols[_bestIndex].Order ; }
        }
        void Eval(Solution Sol) {
            SlimeGame SG = new SlimeGame(_data.GameData);
            UI tempdata = SG.GetUI();
            int sum1 = 0;
            int sum2 = 0;
            for (int j = 0; j < tempdata.GetPlayer(_side ^ 1).Slimes.Count; j++)
            {
                sum1 += tempdata.GetPlayer(_side ^ 1).Slimes[j].HP;
            }
            List<int> temporder = Sol.Order;
            for (int i = 0; i < temporder.Count; i++)
            {
                Slime S = tempdata.GetPlayer(_side).Slimes[temporder[i]];
                ActionSet.DoAction(S, tempdata, _actionlist[i], _side, false);
            }
            for (int j = 0; j < tempdata.GetPlayer(_side ^ 1).Slimes.Count; j++)
            {
                sum2 += tempdata.GetPlayer(_side ^ 1).Slimes[j].HP;
            }
            Sol.Fitness = sum1 - sum2;
        }
        void BestCounter()
        {
            _num = 0;
            for (int i = 0; i < _sols.Count; i++)
            {
                if (_sols[i].Fitness == _bestSol)
                {
                    ++_num;
                }
            }
        }
    }
}
